package network;

import java.io.*;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchserver {
    //服务器专用的socket,用来和客户端建立连接
    private ServerSocket serverSocket =null;

    public TcpEchserver(int port) throws IOException {
       serverSocket =new ServerSocket(port);
    }
    //启动服务器
    public  void start() throws IOException {
        System.out.println("服务器启动");
        //方法二：创建线程池
        //      解决了频繁创建销毁的问题
        //      如果只创建不销毁，导致线程池积存大量线程.
        ExecutorService pool = Executors.newCachedThreadPool();
        while(true){
            // 通过 accept 方法来 "接听电话", 然后才能进行通信， 和客户端建立连接
            Socket clientSocket =serverSocket.accept();
        /*//方法一：使用多线程实现处理多个客户端请求
                          .缺点需要频繁的创建与销毁.
               Thread thread = new Thread(() ->{
                   processConnection(clientSocket);
               });
               thread.start();
               */
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    processConnection(clientSocket);
                }
            });
        }
    }

    public void processConnection(Socket clientSocket) {
        System.out.printf("[%s:%d] 客户端上线！\n",clientSocket.getInetAddress(),clientSocket.getPort());
        try(OutputStream outputStream = clientSocket.getOutputStream();
            InputStream inputStream = clientSocket.getInputStream()) {
            // 读取请求
            Scanner scanner = new Scanner(inputStream);
            //客户端可能有多个请求,所以使用循环来处理
            while(true){
                if(!scanner.hasNext()){
                    //hasNext()方法判断输入(文件,字符串,键盘等输入流)是否还有下一个输入项,若有,返回true,反之false.
                    //hasNext会等待客户端那边的输入,即会阻塞等待输入源的输入
                    //当客户端那边关闭了连接,输入源也就结束了,没有了下一个数据,说明读完了,此时hasNext()就为false了

                    //读取完毕，客户端会断开连接。产生读取完毕
                    System.out.printf("[%s:%d] 客户端下线！",clientSocket.getInetAddress(),clientSocket.getPort());
                    break;
                }
                //1.读取请求并解析，这里主要隐藏的约定，next读的时候要读到空白符才会结束。
                //  因此就要求客户端发来的请求必须嗲有空白符。比如\n或者空格
                String request = scanner.next();
                //2. 根据请求计算响应
                String reponse =process(request);
                //3.把响应返回客户端
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(reponse);
                //刷新缓冲区,保证当前写入的数据发送出去
                printWriter.flush();
                //日志
                System.out.printf("[%s:%d] rep: %s,reps: %s\n",clientSocket.getInetAddress(),clientSocket.getPort(),
                                    request,reponse);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchserver server = new TcpEchserver(9090);
        server.start();
    }
}
